﻿using DefCore.Core;
using DefCore.Interfaces;
using Ivory;
using Krypton;
using Krypton.Lights;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DefCore.AI.Pathing;

namespace DefCore.Actors
{
    public abstract class Actor : EntityBase, IPathable, IHealthController
    {
        //Fields
        public override Light2D EntityLight
        {
            get { return null; }
        }
        public override ShadowHull EntityHull
        {
            get { return null; }
        }

        protected WaypointPath _ActorPath;
        protected Texture2D ShadowedOutline { get; set; }

        public ActorAlertIconState IconType { get; set; }
        public ActorAlertState AlertStatus { get; protected set; }
        public ActorType AgressionMode { get; protected set; }        

        public IActorBehaviourController BehaviourControler { get; protected set; }

        #region IPathable
        public float ActorSpeed
        {
            get;
            protected set;
        }
        public bool IsControlled
        {
            get;
            set;
        }
        public float Rotation
        {
            get;
            set;
        }
        #endregion

        #region IHealthController
        public int CurrentHealth
        {
            get;
            private set;
        }

        private int _MaxHealth = 10;
        public int MaxHealth
        {
            get { return _MaxHealth; }
            protected set
            {
                _MaxHealth = value;
                CurrentHealth = value;
            }
        }
        #endregion

        //ctor  
        public Actor(DungeonPos position, IActorBehaviourController behaviourControl, ActorType agressionMode, int maxHealth, Vector2 size)
            : base(Objects.LevelInstance)
        {
            this.Position = position;
            this.Size = size;
            this.AlertStatus = ActorAlertState.LOW;
            this.BehaviourControler = behaviourControl;
            this.AgressionMode = agressionMode;
            this.MaxHealth = maxHealth;
            this.IsSelectable = true;
            this.ActorSpeed = 3f;
        }

        //Methods
        private void OnPathFinished(object sender, EventArgs e)
        {
            //Pathing finished, go into instruction state
            BehaviourControler.AIState = ActorAIState.INSTRUCTION_SET;
        }

        protected abstract void OnCreate();
        protected abstract void OnDelete();

        protected abstract void RenderActor(SpriteBatch batch, GameTime time);
        protected abstract void SolveActor(InputControl control, GameTime time);
        
        public sealed override void Create()
        {
            OnCreate();
        }
        public sealed override void Delete()
        {
            OnDelete();
        }

        public sealed override void Render(SpriteBatch batch, GameTime time)
        {
            //Draw the Aggression Circle
            //batch.Draw(HealthbarService.Instance.GenerateHealthbar(this), new Rectangle(0, 0, 0, 0), Color.White);
            
            //Draw the Selectable Shadow
            if ((IsSelected || IsHoverTarget) && ShadowedOutline != null)
                batch.Draw(ShadowedOutline, HitBox, null, Color.Red, this.Rotation, Size / 2f, SpriteEffects.None, 0f);
            
            //Draw the Actor Texture using the Model Controller
            RenderActor(batch, time);

            //Draw the Icon
            //batch.Draw(ShadowedOutline, HitBox, null, Color.Red, this.Rotation, Size / 2f, SpriteEffects.None, 0f);

            //Draw the Healthbar Textire
            batch.Draw(HealthbarService.Instance.GenerateHealthbar(this), new Rectangle(HitBox.X, HitBox.Y, 64, 32), Color.White);
        }
        public override void Solve(InputControl control, GameTime time)
        {
            SolveActor(control, time);

            switch (BehaviourControler.AIState)
            {
                case ActorAIState.IDLE:
                    {
                        BehaviourControler.AIState = BehaviourControler.IdleState();
                        break;
                    }

                case ActorAIState.PATHING:
                    {
                        if (_ActorPath != null)
                            _ActorPath.UpdatePath(time);
                        else
                            throw new ApplicationException("Error, pathing state reached, but path not set");
                        break;
                    }

                case ActorAIState.INSTRUCTION_SET:
                    {
                        BehaviourControler.AIState = BehaviourControler.InstructionSetState();
                        break;
                    }
                case ActorAIState.FINISHED:
                    {
                        BehaviourControler.AIState = BehaviourControler.FinishedState();
                        break;
                    }

                default:
                    break;
            }

            
        }

        public void Damage(int amount)
        {
            CurrentHealth -= amount;

            if (CurrentHealth <= 0)
            {
                //WE DIED 
                Delete();
            }
        }
        public void Heal(int amount)
        {
            CurrentHealth = (CurrentHealth + amount) >= CurrentHealth ? CurrentHealth : (CurrentHealth + amount);
        }

        public void PathTo(DungeonPos position)
        {
            //New path to will result in us stopping, if a path cant be found we sill just stop!
            BehaviourControler.AIState = ActorAIState.IDLE;

            IEnumerable<Waypoint> path = PathFinder.FindPathBetween(Position, position);
            if (path.Count() == 0) 
            { 
                //No Path - notify the user by drawing an Question icon;
                this.IconType = ActorAlertIconState.QUESTION;
                return;
            }
            else
            {
                BehaviourControler.AIState = ActorAIState.PATHING;
                if (_ActorPath != null)
                {
                    _ActorPath.PathFinished -= OnPathFinished;
                    _ActorPath = null;
                }

                _ActorPath = new WaypointPath(this, path);
                _ActorPath.PathFinished += OnPathFinished;
                _ActorPath.Start();
            }
        }               
    }
}
